{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Pandas 字符串填充与对齐详解\n",
    "\n",
    "在数据清洗、报表输出或文本格式化过程中，我们经常需要将字符串对齐到指定宽度，或者对其进行补全。本教程将系统介绍 Pandas 提供的几种常用字符串填充与对齐方法，包括 `str.pad()`, `str.ljust()`, `str.rjust()`, `str.center()` 以及 `str.zfill()`，并通过完整示例展示它们的使用技巧与注意事项。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 1. 导入库并准备示例数据\n",
    "\n",
    "示例数据包含不同长度的字符串以及缺失值，方便观察各方法的行为。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "import pandas as pd\n",
    "\n",
    "s = pd.Series(['NY', 'LA', 'London', 'Tokyo', '新加坡', None, '123'], name='city_code')\n",
    "print('原始 Series:')\n",
    "print(s)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 2. `str.pad()` —— 灵活的填充方法\n",
    "\n",
    "`Series.str.pad(width, side='left', fillchar=' ')` 可以在指定方向填充单个字符，直到字符串长度达到 `width`。\n",
    "- `side`: 可选 `'left'`, `'right'`, `'both'`，决定在哪一侧填充。\n",
    "- `fillchar`: 填充字符，必须是长度为 1 的字符串。\n",
    "- 遇到 `NaN` 时返回 `NaN`，后续可结合 `.fillna()` 处理。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('默认右侧填充到长度 8:')\n",
    "print(s.str.pad(width=8))\n",
    "\n",
    "print('\\n左侧填充 (side=\"left\")，填充字符为 \"-\" :')\n",
    "print(s.str.pad(width=8, side='left', fillchar='-'))\n",
    "print('\\n双侧平均填充 (side=\"both\")，填充字符为 \"*\":')\n",
    "print(s.str.pad(width=10, side='both', fillchar='*'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 3. `str.ljust()` 与 `str.rjust()` —— 左右对齐\n",
    "\n",
    "当需要简单地向左或向右对齐时，可使用：\n",
    "- `Series.str.ljust(width, fillchar=' ')`: 右侧填充。\n",
    "- `Series.str.rjust(width, fillchar=' ')`: 左侧填充。\n",
    "\n",
    "下面以一个商品编码示例演示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "product_codes = pd.Series(['A1', 'B234', 'C56', 'D'])\n",
    "\n",
    "print('左对齐 (ljust)，右侧用空格补齐到 6 位:')\n",
    "print(product_codes.str.ljust(width=6))\n",
    "\n",
    "print('\\n右对齐 (rjust)，左侧用 0 补齐到 6 位:')\n",
    "print(product_codes.str.rjust(width=6, fillchar='0'))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 4. `str.center()` —— 居中对齐\n",
    "\n",
    "`Series.str.center(width, fillchar=' ')` 会在两侧添加填充字符，使文本居中显示。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "names = pd.Series(['Alice', 'Bob', 'Cathy'])\n",
    "\n",
    "print('居中对齐，填充字符为 = :')\n",
    "print(names.str.center(width=10, fillchar='='))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 5. `str.zfill()` —— 数字字符串左侧补零\n",
    "\n",
    "`Series.str.zfill(width)` 专门用于在数字字符串左侧补零，常用于对齐编号、流水号等。遇到正负号时，会在符号后补零。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "codes = pd.Series(['12', '5', '-42', '+7', '12345'])\n",
    "\n",
    "print('补零到 4 位:')\n",
    "print(codes.str.zfill(4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 6. 链式操作示例\n",
    "\n",
    "将多个字符串方法链式调用，可以在一行中完成复杂的清洗逻辑。例如：去除空格、统一大小写、再补齐到固定宽度。链式写法不仅更简洁，也避免了创建中间变量。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "raw_ids = pd.Series(['  a1', 'B2  ', '  c003', None])\n",
    "\n",
    "clean_ids = (\n",
    "    raw_ids\n",
    "    .str.strip()\n",
    "    .str.upper()\n",
    "    .str.zfill(4)\n",
    ")\n",
    "\n",
    "print('链式处理后的结果:')\n",
    "print(clean_ids)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 7. 处理缺失值的策略\n",
    "\n",
    "大多数 `.str` 方法在遇到 `NaN` 时都会返回 `NaN`。如果希望在填充后统一替换缺失值，可结合 `.fillna()` 使用。也可以在调用字符串方法前使用 `.fillna()` 为缺失值指定默认字符串。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "print('原始含缺失值的 Series:')\n",
    "print(s)\n",
    "\n",
    "print('\\n使用 str.pad 之后再填充缺失值:')\n",
    "print(s.str.pad(width=8, side='left', fillchar='-').fillna('数据缺失'))\n",
    "\n",
    "print('\\n先将缺失值填充为占位符，再执行 zfill:')\n",
    "print(s.fillna('0').str.zfill(4))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 8. 小结\n",
    "\n",
    "- `str.pad()` 提供最灵活的填充方式，可控制填充方向与字符。\n",
    "- `str.ljust()` / `str.rjust()` / `str.center()` 针对常见的左、右、居中对齐场景。\n",
    "- `str.zfill()` 专用于数字字符串左侧补零，兼容正负号。\n",
    "- 链式调用能让字符串清洗流程更简洁高效。\n",
    "- 面对缺失值时，可在操作前后配合 `.fillna()` 进行处理。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "ml311",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 4
}
